﻿/* HEADER
 * ------
 * © 2009 by Salomon Zwecker 
 * modified by:
 * - 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Shapes.Geometry
{
    /// <summary>
    /// Description of a curve using the quadratic B-Spline algorithm.
    /// </summary>
    public class Spline : PointList<SplinePoint>
    {
        /// <summary>
        /// creates a new quadratic B-Spline curve
        /// </summary>
        /// <param name="points">the ordered spline points describing the curve</param>
        [Obsolete("this constructor overload only exist because of consistency")]
        public Spline(List<SplinePoint> points)
            : base(points.ToArray())
        {
            FitBounding();
        }
        /// <summary>
        /// creates a new quadratic B-Spline curve
        /// </summary>
        /// <param name="points">the ordered spline points describing the curve</param>
        public Spline(params SplinePoint[] points)
            : base(points)
        {
            FitBounding();
        }

        /// <summary>
        /// connects the end of the spline with the beginning
        /// </summary>
        public override void Close()
        {
            IsClosed = true;
        }

        #region Position conversion
        /// <summary>
        /// converts the given position to local coordinates
        /// </summary>
        /// <param name="globalPosition">the global position</param>
        /// <returns>the local position</returns>

        public override Vector2 GetLocalPositionOfPoint(SplinePoint globalPosition)
        {
            return _Transform.TransformGlobalToLocal(globalPosition.Position);
        }

        /// <summary>
        /// converts the given postion to global coordinates
        /// </summary>
        /// <param name="localPosition">the local position</param>
        /// <returns>the global position</returns>
        public override Vector2 GetGlobalPositionOfPoint(SplinePoint localPosition)
        {
            return _Transform.TransformLocalToGlobal(localPosition.Position);
        }

        /// <summary>
        /// converts the given position to local coordinates
        /// </summary>
        protected override void ToLocalCoordinates(ref SplinePoint outPoint)
        {
            _Transform.TransformGlobalToLocal(ref outPoint.Position);
        }

        /// <summary>
        /// converts the given position to global coordinates
        /// </summary>
        /// <param name="outPoint"></param>
        protected override void ToGlobalCoordinates(ref SplinePoint outPoint)
        {
            _Transform.TransformLocalToGlobal(ref outPoint.Position);
        }

        /// <summary>
        /// Returns the given point as a Vector2
        /// </summary>
        /// <param name="point">the point</param>
        /// <returns>the vector of the point</returns>
        protected override Vector2 GetVectorOfPoint(SplinePoint point)
        {
            return point.Position;
        }
        #endregion

        /// <summary>
        /// fits the bounding
        /// </summary>
        internal override void FitBounding()
        {
            Vector2 smallPos = new Vector2(float.MaxValue, float.MaxValue);
            Vector2 farPos = new Vector2(float.MinValue, float.MinValue);

            foreach (SplinePoint p in _Points)
            {
                #region get smallest point

                if (p.Position.X < smallPos.X)
                    smallPos.X = p.Position.X;
                if (p.Position.Y < smallPos.Y)
                    smallPos.Y = p.Position.Y;

                #endregion
                #region get farest point

                if (p.Position.X > farPos.X)
                    farPos.X = p.Position.X;
                if (p.Position.Y > farPos.Y)
                    farPos.Y = p.Position.Y;

                #endregion
            }

            _BorderLength = 0;
            foreach (Line line in _Lines)
            {
                line.SetPoints(line.StartPoint - smallPos, line.EndPoint - smallPos);
                _BorderLength += line.BorderLength;
            }
            for (int i = 0; i < _Points.Count; i++)
            {
                _Points[i] -= smallPos;
            }

            /*
             * TODO: fit bounding better (as close as possible to the curves)
             */

            _Transform._Position += smallPos;
            _Transform._Width = farPos.X - smallPos.X;
            _Transform._Height = farPos.Y - smallPos.Y;
            _Transform._IsDirty = true;
            _Transform.CallOnChange();
        }

        internal override float GetDistanceToEdge(ref Vector2 point)
        {
            throw new NotImplementedException();
        }

        internal override Vector2 GetNearestPointOnEdge(ref Vector2 point)
        {
            throw new NotImplementedException();
        }

        internal override Vector2 GetPositionFromT(float t)
        {
            throw new NotImplementedException();
        }

        internal override float GetEdgePathValueFromPoint(ref Vector2 point)
        {
            throw new NotImplementedException();
        }
        internal override Vector2 GetNormal(ref Vector2 position)
        {
            throw new NotImplementedException();
        }
        internal override Vector2 GetTangent(ref Vector2 position)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Clones the Spline
        /// </summary>
        /// <returns>An object of the type QuadBSpline</returns>
        public override object Clone()
        {
            Spline obj = new Spline(_Points.ToArray());
            obj._Transform = (Transformation2D)_Transform.Clone();
            return obj;
        }

        /// <summary>
        /// Gets the enumeration type which is mapped to this kind of object
        /// </summary>
        /// <returns>the geometry typee of this object</returns>
        public override GeometryType GetGeometryType()
        {
            return GeometryType.Spline;
        }
    }
}
